Introducción general al uso de R
Clase práctica 04

Autor/a
Afiliación

Ignacio Minoli
minolicnp@gmail.com

Observatorio de Biodiversidad del Bosque Atlántico (OBBA) Instituto de Biología Subtropical (IBS) - Unidad Ejecutora del CONICET - UNaM

Fecha de publicación

21 de agosto de 2024

Las posibilidades gráficas de R fueron una de las bases del éxito del uso de este lenguaje de programación entre investigadores y analistas. Siempre es necesario evaluar el tipo de datos, formato, cantidades y clases para seleccionar cual es el plot más adecuado.

1 Plots en R base

La función plot() del R base ofrece una variadad de opciones, pero en la actualidad es poco utilizado.

Scatterplots

# Uso dos vectores data(mtcars)
attach(mtcars)

x <- mtcars$hp # Number of cylinders
y <- mtcars$disp

# Hago el scatterplot
plot(x, y, main = "Dispersión valores disp y hp",
     xlab = "Number of cylinders (hp)",
     ylab = "Displacement (disp)",
     pch = 19, frame = FALSE
     )
lines(lowess(x, y), col = "blue")

# Argumentos de la función:
x, y: coordenadas de los puntos
main: título del plot
xlab: label del eje x
ylab: label del eje y
pch: tipo de símbolo
frame: con o sin marco

Boxplots

# Boxplot de una variable
boxplot(ToothGrowth$len)

# Boxplot de dos variables
boxplot(len ~ dose, data = ToothGrowth,
        main = 'Plot of length by dose',
        xlab = 'Dose (mg)', ylab = 'Length',
        col = 'lightgray', frame = FALSE
        )

# Argumentos:
len: eje y
dose: eje x
data: data frame
main: título del plot
xlab: label del eje x
ylab: label del eje y
col: color
frame: con o sin marco

Barplots

# Subset
x <- VADeaths[1:3, "Rural Male"]
x
50-54 55-59 60-64 
 11.7  18.1  26.9 
# Barplot de una variable
barplot(x)

# Con todos los elementos del gráfico
barplot(x,
        main = "Death Rates in Virginia",
        names.arg = c("Young", "Adult", "Old"),
        xlab = "Age", ylab = "Rate"
        )

Gráficos de torta

# Creo el df
df <- data.frame(empresas = c("Empresa_A", "Empresa_B","Empresa_C"),
                 cotizacion = c(25, 25, 50)
                 )
df
   empresas cotizacion
1 Empresa_A         25
2 Empresa_B         25
3 Empresa_C         50
# Pie chart o gráfico de torta
pie(df$cotizacion,
    labels=df$empresas,
    radius = 1)

pie(df$cotizacion,
    labels = df$empresas,
    radius = 1,
    col = c("red", "green", "blue")
    )

Histogramas

# Creo el data frame
set.seed(1234)
x <- c(rnorm(200, mean=55, sd=5),
       rnorm(200, mean=65, sd=5)
       )
head(x, 2)
[1] 48.96467 56.38715
# Hago el histograma
hist(x, col = "steelblue")

# Quiero ver mayor detalle en la frecuencia de loa datos. Argumento breaks
hist(x, col = "steelblue", breaks = 30)

2 Plots con otros paquetes

Scatterplots

library(gapminder)
library(ggplot2)

Attaching package: 'ggplot2'
The following object is masked from 'mtcars':

    mpg
library(dplyr)

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
# Gráfico de dispersión avanzado
gapminder %>%
  ggplot(aes(x = lifeExp, y = gdpPercap, size = pop, col = continent)) + 
  geom_point(alpha = 0.5) +
  scale_y_log10()+
  guides(col=guide_legend("My Continents"),
         size=guide_legend("Population"))

Boxplots

library(gapminder)
library(ggplot2)
library(dplyr)

ggplot(gapminder, aes(x = continent, y = lifeExp, fill = continent)) +
      geom_boxplot() +
      geom_jitter(width=0.25, alpha=0.5)

library(gapminder)
library(ggplot2)
library(dplyr)

# Aprovecho los pipes y filtros antes de hacer el plot
gapminder %>% 
  filter(year %in% c(1957,1987,2007)) %>%
  ggplot(aes(x = continent, y = lifeExp, fill = factor(year))) +
  geom_boxplot() + 
  labs(fill = "Year") + 
  geom_point(position = position_jitterdodge(), alpha = 0.3) +
  theme_bw(base_size = 16)

library(gapminder)
library(ggplot2)

# Puedo usar facet para elegir sobre que variable crear los plots
gapminder %>% 
  ggplot(aes(x = continent, y = lifeExp, fill = continent)) +
  geom_boxplot() +
  geom_jitter(width = 0.1, alpha = 0.2) +
  xlab("Continent") + 
  facet_wrap(~year) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Barplots

library(dplyr)
library(plyr)
------------------------------------------------------------------------------
You have loaded plyr after dplyr - this is likely to cause problems.
If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
library(plyr); library(dplyr)
------------------------------------------------------------------------------

Attaching package: 'plyr'
The following objects are masked from 'package:dplyr':

    arrange, count, desc, failwith, id, mutate, rename, summarise,
    summarize
library(ggplot2)
library(dplyr)

# Creo el data set
df_2 <- data.frame(aditivo = rep(c("VC", "OJ"), each=3),
                  dosis = rep(c("0.5", "1", "2"),2),
                  resultado = c(6.8, 15, 33, 4.2, 10, 29.5))

# Ordeno por las 2 variables
df_sorted <- arrange(df_2, dosis, aditivo) 

# Calculo la suma acumulativa de resultado para cada dosis
df_cumsum <- ddply(df_sorted, "dosis",
                   transform, label_ypos=cumsum(resultado)
                   )

# Hago el barplot
ggplot(data = df_cumsum,
       aes(x = dosis, y = resultado, fill = aditivo)
       ) +
  geom_bar(stat="identity") +
  geom_text(aes(y=label_ypos, label=resultado),
            vjust=1.6, 
            color="white",
            size=3.5
            ) +
  scale_fill_brewer(palette="Paired") +
  theme_minimal()

Gráficos de torta

library(webr)
library(ggplot2)

PieDonut(mtcars,
         aes(gear, carb),
         explode = 3,
         r1 = 0.9,
         explodeDonut = TRUE,
         title = "Distribution of carburetors by gears",
         star = 3*pi/2,
         labelposition=0
         )

Histogramas

# Creo el data frame
set.seed(1234)
wdata <- data.frame(sex = factor(rep(c("F", "M"), each=200)),
                    weight = c(rnorm(200, 55), rnorm(200, 58))
                    )

# Exploro el set de datos
head(wdata, 4)
  sex   weight
1   F 53.79293
2   F 55.27743
3   F 56.08444
4   F 52.65430
# Hago el histograma
library(ggplot2)

ggplot(wdata, aes(x = weight)) +
geom_histogram(aes(color = sex, fill = sex),
               position = "identity",
               bins = 30,
               alpha = 0.4
               ) +
scale_color_manual(values = c("#00AFBB", "#E7B800")) +
scale_fill_manual(values = c("#00AFBB", "#E7B800"))

Intervalos de confianza

library(gplots)

Attaching package: 'gplots'
The following object is masked from 'package:stats':

    lowess
plotmeans(ToothGrowth$len ~ ToothGrowth$dose, mean.labels=T)

3 Graphics devices

Hay dos opciones: screen device y file device. Un screen device es simplemente la ventana que me permite visualizar y un file device es cuando es guardado en un archivo (aunque sea en temporales) y puede ser en una variedad de formatos.

En Mac: quartz() abre una graphic device nuevo
En Windows windows() abre una graphic device nuevo
En Unix/Linux x11() abre una graphic device nuevo
Se cierran con dev.off() o graphics.off()
Ejercicio 04.1
1- Re hacer cualquiera de los gráficos anteriores.
2- Abrir un graphic device según tu SO.
3- Re hacer otro de los gráficos anteriores.
¿Qué ocurrió?
4- Correr el comando dev.off() y ver que ocurre.

4 Partes de un gráfico

Las partes necesarias para que un gráfico esté completo fueron detallados en la teoría y están pensados desde un punto de vista informativo e independiente para el lector.

Partes en un gráfico de R base:

  • Datos

  • Colores

  • Símbolos - lineas - barras

  • Título

  • Leyenda

  • Ticks - escalas - ejes

  • Etiquetas ejes

  • Márgenes

Partes en un plot R base

Partes en un plot R ggplot

Partes en un plot R ggplot

Las partes de un plot guardan estrecha relación con el guardado y tamaño final del mismo. Gráficos pequeños no podrán tener muchos elementos e información adicional. Ejemplo:

Ejemplo de lo que NO hay que hacer en un plot

Ejemplo de lo que NO hay que hacer en un plot

5 Guardado de un gráfico

Este es un aspecto relacionado a los plots muy importante para optimizar el trabajo que conlleva crear un plot. Si bien en RStudio está la posibilidad de guardar un plot desde la sección “Plots” con el botón “Export” yo recomiendo guardar el plot en un archivo en el directorio deseado y visualizarlo al tamaño real con un visor de imágenes del SO.

¿Por qué esta propuesta? Muchas veces creamos plots con una resolución muy alta (e.g., 1200 dpi - dots per inch) y el tamaño largo x ancho es muy grande (e.g., 21 x 29.7 cm). Si este plot es para un póster de congreso sería adecuado … ¿Pero qué pasa si en un journal me permiten figuras con medidas máximas 4 x 7 cm? Al reducir a ese tamaño la imagen tamaño A4: no se leen las fuentes, los símbolos no se diferencian, detalles de un mapa no son observables, etiquetas o nombres son ilegibles para el lector, etc.

Con base en todo esto, aquí veremos un ejemplo que sí sirva. En este ejercicio vamos a crear un plot “jugando” con su tamaño y resolución.

Ejemplo Opción 1

Problema: Quiero guardalo en .png pero en un tamaño y resolución determinado por el journal adonde será publicado.

Solución: Guardarlo en .png y especificar tamaños.

# Seteo la ruta y el archivo a crear. En svg no hace falta colocar tamaños.
png('/home/ignacio/Desktop/png_ejemplo.png',
    width = 10,
    height = 16,
    units = "cm",
    res = 600
    )
# Gráfico de dispersión avanzado
gapminder %>%
  ggplot(aes(x = lifeExp, y = gdpPercap, size = pop, col = continent)) + 
  geom_point(alpha = 0.5) +
  scale_y_log10()+
  guides(col=guide_legend("My Continents"),
         size=guide_legend("Population"))

# Cierro el graphic device
graphics.off()
Ejercicio 04.2
1- Abrir el .png con un visor de imágenes.
2- ¿Qué ocurrió?
3- ¿Cómo puedes arreglarlo? Pro-tip: jugar con los argumentos width, height y dpi para luego pegarlo en un word.

Ejemplo Opción 2

Problema: Quiero guardalo en .pdf pero en un gran tamaño y resolución para que sea impreso y revisado.

Solución: Guardarlo en .pdf y especificar tamaños.

pdf(file = "/home/ignacio/Desktop/margen_barplot.pdf", # directorio para el pdf
    width = 4, # ancho del plot en pulgadas
    height = 4, # alto del plot en pulgadas
    bg = "white", # color de fondo
    colormodel = "cmyk" # modelo del color
    )
# Configuro el device para el plot poniendo algunos márgenes 0 (cero).
# Así optimizo el tamaño de la imagen y remuevo excesos de bordes.
par(mar=c(2, 2, 1, 0))

# Con todos los elementos del gráfico
x <- VADeaths[1:3, "Rural Male"]
barplot(x,
        main = "Death Rates in Virginia",
        names.arg = c("Young", "Adult", "Old"),
        xlab = "Age", ylab = "Rate"
        )

# Cerrar el device. Recién allí se crea el archivo!
graphics.off()
Ejercicio 04.3
1- Abrir el .pdf con un visor de pdfs.
2- ¿Qué ocurrió? ¿Falta alguna parte del plot?
3- ¿Qué pasa si agregas al directorio con el pdf, el argumento paper = "A4"? ¿Se soluciona?
4- ¿Cómo puedes arreglarlo? Pro-tip: jugar con los argumentos mar dentro de la función par().

Ejemplo Opción 3

Problema: No sé usar bien las funciones / argumentos de R y lo quiero editar a mano

Solución: Guardarlo en .svg y editarlo por ejemplo con Inkscape. No recomendado.

# Seteo la ruta y el archivo a crear. En svg no hace falta colocar tamaños.
svg('/home/ignacio/Desktop/vec_ejemplo.svg')
#
# Gráfico de dispersión avanzado
gapminder %>%
  ggplot(aes(x = lifeExp, y = gdpPercap, size = pop, col = continent)) + 
  geom_point(alpha = 0.5) +
  scale_y_log10()+
  guides(col=guide_legend("My Continents"),
         size=guide_legend("Population"))

# Cierro el graphic device
graphics.off()

6 Funciones gráficas interactivas

Son funciones gráficas de R avanzadas y diseñadas para grandes volúmenes de datos o que necesitan ser observadodos en varias dimensiones.

library(gplots)
library(ggplot2)
library(plotly)

Attaching package: 'plotly'
The following objects are masked from 'package:plyr':

    arrange, mutate, rename, summarise
The following object is masked from 'package:ggplot2':

    last_plot
The following object is masked from 'package:stats':

    filter
The following object is masked from 'package:graphics':

    layout
library(gapminder)

p <- gapminder %>%
  filter(year==1977) %>%
  ggplot(aes(gdpPercap, 
              lifeExp,
              size = pop,
              color=continent)
          ) +
  geom_point() +
  theme_bw()

p

ggplotly(p)

En el caso de hacer un PCA o un gráfico de dispersión entre 3 variables:

library(car)
Loading required package: carData

Attaching package: 'car'
The following object is masked from 'package:dplyr':

    recode
library(rgl)
library(palmerpenguins)

bill.l <- penguins$bill_length_mm
flip.l <- penguins$flipper_length_mm
mass.g <- penguins$body_mass_g

p3d <- scatter3d(x = bill.l,
                 y = flip.l,
                 z = mass.g,
                 groups = penguins$species,
                 surface=FALSE,
                 grid = FALSE,
                 ellipsoid = TRUE,
                 surface.col = c("red", "blue", "black")
                 )
Loading required namespace: mgcv
p3d
NULL
rglwidget()

Otros tipos de usos para estos plots en 3D son mapas de batimetría, topográficos con altitud, fondos marinos, pendientes de ríos, cuencas hidrográficas, cartografía de cuevas, etc.

7 Ejercicio 04.1 correr este comando

1- Llamar a un set de datos propio con read_csv().

2- Si no poseen un set de datos propio, pueden utilizar alguno de los set de datos que dispone R en la url https://stat.ethz.ch/R-manual/R-devel/library/datasets/html/00Index.html. Pueden simplemente tipeando en RStudio el nombre del data set:

library(datasets)

# Por ejemplo:
head(beaver1)
  day time  temp activ
1 346  840 36.33     0
2 346  850 36.34     0
3 346  900 36.35     0
4 346  910 36.42     0
5 346  920 36.55     0
6 346  930 36.69     0

3- Analizar el tipo de datos que contiene el dataframe o tibble.

4- Hacer un gráfico que muestre adecuadamente los datos y guardarlo como un png.